import {BATTLE, BATTLE_FLOW_TYPE, BOOLEAN, GAME_OVER_TYPE, INS_KEY, REDIS_KEYS} from "../configs/config";
import UserDao from "../dao/user-dao";
import BattleDao from "../dao/battle-dao";
import BattleFlowDao from "../dao/battle-flow-dao";
import BattleHistoryDao from "../dao/battle-history-dao";
import BattleUserDao from "../dao/battle-user-dao";
import UserStateDao from "../dao/user-state-dao";
import FileUtils from "./file-utils";
import DateUtils from "./date-utils";
import RedisUtils from "./redis-utils";
import BoardUtils from "./board-utils";
import InsUtils from "./ins-utils";

const fileUtil = new FileUtils();
const dateUtils = new DateUtils();
const redisUtils = new RedisUtils();
const boardUtils = new BoardUtils();
const insUtils = new InsUtils();

class BattleUtils {


    /**
     * 获取对战数据
     * @param userId
     * @param battleId
     * @param jobInstance
     * @returns {Promise<[]>}
     */
    getBattleData = async (userId: string, battleId: string, jobInstance: any) => {
        const log = global.logUtils.createContext('BattleUtils', 'getBattleData', {userId, battleId});
        log.info(`请求参数:${battleId}`);
        // 查询该房间的用户信息
        const userResults: any = await BattleUserDao.queryBattleUserTable([['battle_id', battleId]]);
        if (userResults.length === 0) {
            log.info(`对战数据不存在, battleId:[${battleId}]`);
            return null;
        } else {
            log.info(`已获取到数据`, userResults);
            const battleData = [];
            const battleUserTime = jobInstance.getBattleTime(battleId);
            if (!battleUserTime) {
                log.info(`无法获取到对局相关时间数据`, battleUserTime);
                return null;
            }

            for (let i = 0; i < userResults.length; ++i) {
                const battleUser = userResults[i];
                const user: any = await UserDao.getUserByPrimaryKey(battleUser.userId);
                const roomUser = await BattleHistoryDao.getLastBattleMapHistory(battleId, battleUser.userId);
                const timeUser = battleUserTime.find((user: any) => user.userId === battleUser.userId);
                // 查询历史记录
                const historyMoveStep: any[] = [];
                const dbHistoryStep: any = await BattleHistoryDao.getAllHistoryMoveStep(battleId, battleUser.userId);
                if (dbHistoryStep && dbHistoryStep.length > 0) {
                    dbHistoryStep.map((step: any) => {
                        historyMoveStep.push({
                            gameMap: JSON.parse(step.gameMap),
                            chessBox: JSON.parse(step.lastChessBox),
                            lastChess: JSON.parse(step.lastChess),
                        });
                    });
                }
                battleData.push({
                    score: user.score,
                    userId: user.userId,
                    userName: user.userName,
                    iconUrl: fileUtil.getShowPath(user.iconUrl),
                    first: battleUser.first,
                    gameMap: JSON.parse(roomUser.gameMap),
                    isRedMove: roomUser.isRedMove,
                    stepCount: roomUser.stepCount,
                    lastChess: JSON.parse(roomUser.lastChess),
                    chessBox: JSON.parse(roomUser.lastChessBox),
                    allTime: timeUser.allTime,
                    stepTime: timeUser.stepTime,
                    basicAllTime: BATTLE.TOTAL_TIME_SECONDS,
                    basicStepTime: BATTLE.STEP_TIME_SECONDS,
                    readSeconds: BATTLE.READ_SECONDS,
                    historyMoveStep: historyMoveStep,
                    offlineTime: battleUser.offlineTime,
                });
            }
            return battleData;
        }
    }

    /**
     * 胜利后计算双方得分
     * @param gameMap
     * @param type：0001-对局，0002-认输，0003-逃跑, 0004-超时
     * @param stepCount：对局步数
     * @constructor
     */
    calcScore = (gameMap: any, type: string, stepCount: number) => {
        // 两步之内，双方得分为0
        if (stepCount <= 2) {
            return {
                winScore: 0,
                failScore: 0,
                // 是否要计分(两步之内不计分)
                isValidScore: false,
            };
        }
        let redScore = 0;
        let blackScore = 0;
        gameMap.map((chess: any) => {
            if (chess.id === 'black') {
                blackScore += 1;
            } else {
                redScore += 1;
            }
        });
        // 和棋情况下，只优势方得分（少量的分）
        if (type === GAME_OVER_TYPE.USER_PEACE) {
            const score = Math.max(redScore, blackScore) - Math.min(redScore, blackScore);
            return {
                // 优势方得分
                winScore: score,
                // 劣势方不扣分
                failScore: 0,
                isValidScore: true,
            };
        } else {
            const lastScore = (Math.max(redScore, blackScore) - Math.min(redScore, blackScore));
            return {
                winScore: lastScore,
                failScore: -lastScore,
                isValidScore: true,
            };
        }
    }

    /**
     * 检查是否有待处理的请求
     * 如：悔棋、求和等
     * @param userId
     * @return false: 无, true：有
     */
    checkWaitingRequest = async (userId: string) => {
        const userState = await UserStateDao.getUserStateByUserId(userId);
        if (!userState) {
            return true;
        }
        const battleId = userState.battleId;
        const battleData: any = await BattleDao.queryBattleTable([['id', battleId]]);
        if (!battleData || battleData.length === 0) {
            return false;
        } else {
            const [battle] = battleData;
            const { sendUserId } = battle;
            return !!sendUserId;
        }
    }

    /**
     * 检查短时间内重复发送
     * @param userId
     * @param limitSeconds
     * @param battleFlowType
     */
    checkShortTimeRepeatSend = async (userId: string, limitSeconds: number, battleFlowType: BATTLE_FLOW_TYPE) => {
        const userState = await UserStateDao.getUserStateByUserId(userId);
        if (!userState) {
            return true;
        }
        // 获取该用户最近发送的求和请求
        const battleId = userState.battleId;
        const lastBattleFlow: any = await BattleFlowDao.getLastBattleFlowBy(battleId, userId, battleFlowType);
        if(lastBattleFlow) {
            // 判断时间间隔
            const createTime: Date = dateUtils.strToDate(lastBattleFlow.createTime);
            const timeSeconds = dateUtils.dateDiffSeconds(createTime, new Date());
            if(timeSeconds <= limitSeconds) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查悔棋状态
     * @param userId
     * @param battleId
     * @param roomId
     * @return true: 可悔棋, false: 不能悔棋
     */
    checkBackMoveStatus = async (userId: any, battleId: any, roomId: any) => {
        const where = [];
        where.push(['user_id', userId]);
        where.push(['battle_id', battleId]);
        where.push(['room_id', roomId]);
        where.push(['type', BATTLE_FLOW_TYPE.BACK_MOVE]);
        where.push(['result', BOOLEAN.SHORT_YES]);
        const battleFlowRows: any = await BattleFlowDao.queryBattleFlowTable(where);
        return battleFlowRows.length < BATTLE.BACK_MOVE_COUNT;
    }

    /**
     * 计算优势方
     * @param gameMap
     */
    calcBestUser = (gameMap: any) => {
        let redScore = 0;
        gameMap.map((chess: any) => {
            if (chess.id === 'black') {
                redScore -= 1;
            } else {
                redScore += 1;
            }
        });
        // 判定优势方(先手或后手)
        return redScore >= 0;
    }

    /**
     * 计算时间差
     * @param startDate
     * @param endDate
     * @return 差值(ms)
     */
    calcTimeDiff = (startDate: Date, endDate: Date) => {
        if(startDate && endDate) {
            return endDate.getTime() - startDate.getTime();
        }
        return null;
    }

    /**
     * 清除对战缓存
     * @param battleId
     * @param userId
     */
    clearBattleCache = async (battleId: string, userId: string) => {
        // 快速检索的key
        const battleOfflineKeys = await redisUtils.getStr(REDIS_KEYS.BATTLE_OFFLINE_KEYS);
        // 存储数据的key
        const redisKey = `${REDIS_KEYS.BATTLE_OFFLINE_KEY}:${battleId}:${userId}`;

        await redisUtils.delete(redisKey);
        const battleOfflineKeyArray = battleOfflineKeys ? JSON.parse(battleOfflineKeys) : [];
        const newBattleOfflineKeyArray = battleOfflineKeyArray.filter((key: string) => key !== redisKey);
        await redisUtils.setStr(REDIS_KEYS.BATTLE_OFFLINE_KEYS, JSON.stringify(newBattleOfflineKeyArray));
    }

    /**
     * 保存移动棋子时的数据
     * @param user
     * @param enemy
     * @param to
     * @param chessBox
     */
    saveMoveChessData = async (user: any, enemy: any, to: any, chessBox: any) => {
        const jobInstance = insUtils.getIns(INS_KEY.JOB_KEY);

        /** === 新增对战历史步骤表的数据 === */

        const battleUserTime = jobInstance.getBattleTime(user.battleId);
        const userTime = battleUserTime.find((item: any) => item.userId === user.userId);
        const enemyTime = battleUserTime.find((item: any) => item.userId === enemy.userId);
        // 我方的数据
        const userMapHistory = await BattleHistoryDao.getLastBattleMapHistory(user.battleId, user.userId);
        const userGameMap = boardUtils.tryMoveChess(JSON.parse(userMapHistory.gameMap), to);
        const userStepTime = userTime.allTime < 0 ? userTime.stepTime : BATTLE.STEP_TIME_SECONDS;
        const userStepCount = userMapHistory.stepCount + 1;
        const userIsRedMove = !userMapHistory.isRedMove;
        const userLastChess = JSON.stringify(to);
        const userBoxChess = JSON.stringify(chessBox);
        const userThinkTime = this.calcTimeDiff(dateUtils.strToDate(userMapHistory.createTime), new Date());
        await BattleHistoryDao.createBattleMapHistory(user.battleId, user.userId, userGameMap, userIsRedMove,
            userStepCount, userThinkTime, userLastChess, userBoxChess, userTime.allTime, userStepTime);

        // 敌方的数据，棋子进行坐标转换
        const enemyToChessBox = JSON.stringify({
            ...chessBox,
            x: to.x,
            y: to.y
        });

        const enemyMapHistory = await BattleHistoryDao.getLastBattleMapHistory(enemy.battleId, enemy.userId);
        const enemyGameMap = boardUtils.tryMoveChess(JSON.parse(enemyMapHistory.gameMap), to);
        const enemyStepTime = enemyTime.allTime < 0 ? enemyTime.stepTime : BATTLE.STEP_TIME_SECONDS;
        const enemyStepCount = enemyMapHistory.stepCount + 1;
        const enemyIsRedMove = !enemyMapHistory.isRedMove;
        const enemyLastChess = JSON.stringify(to);
        const enemyThinkTime = this.calcTimeDiff(dateUtils.strToDate(enemyMapHistory.createTime), new Date());
        await BattleHistoryDao.createBattleMapHistory(enemy.battleId, enemy.userId, enemyGameMap, enemyIsRedMove,
            enemyStepCount, enemyThinkTime, enemyLastChess, enemyToChessBox, enemyTime.allTime, enemyStepTime);

        // 更新落子方
        await BattleDao.updateBattleCurrIsRedMove(user.battleId, userIsRedMove);
    }
}

// 导出组件
export default BattleUtils;